﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using Microsoft.DirectX.DirectInput;
using System.Runtime.InteropServices;

namespace FortDoneQuicker
{
    class DFcommands
    {
        private static DFcommands instance = null;
        public static DFcommands Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new DFcommands();
                }
                return instance;
            }
        }
        private DFcommands()
        {
        }

        //general
        private int getWindowHandle()
        {
            //check if DF is running
            Process[] proc = Process.GetProcessesByName("Dwarf Fortress");
            if (proc.Length == 0)
            {
                throw new Exception("Can't detect an active Dwarf Fortress session.");
            }

            int hWnd = (int)proc[0].MainWindowHandle;
            return hWnd;
        }
        private void moveCursor(int hWnd, int startRowIndex, int startColumnIndex, int stopRowIndex, int stopColumnIndex)
        {
            //vertical movement
            int deltaRow = stopRowIndex - startRowIndex;
            while (deltaRow != 0)
            {
                if (deltaRow > 0)
                {
                    Keyboard.Instance.keyTap(hWnd, KeyboardKey.downArrow);
                    deltaRow--;
                }
                else if (deltaRow < 0)
                {
                    Keyboard.Instance.keyTap(hWnd, KeyboardKey.upArrow);
                    deltaRow++;
                }
            }

            //horizontal movement
            int deltaColumn = stopColumnIndex - startColumnIndex;
            while (deltaColumn != 0)
            {
                if (deltaColumn > 0)
                {
                    Keyboard.Instance.keyTap(hWnd, KeyboardKey.rightArrow);
                    deltaColumn--;
                }
                else if (deltaColumn < 0)
                {
                    Keyboard.Instance.keyTap(hWnd, KeyboardKey.leftArrow);
                    deltaColumn++;
                }
            }
        }

        //digging
        private void findRectangleDig(Action[,] grid, out int ulRowIndex, out int ulColumnIndex, out int brRowIndex, out int brColumnIndex)
        {
            ulRowIndex = ulColumnIndex = int.MaxValue;
            brRowIndex = brColumnIndex = int.MinValue;

            for (int i = 0; i < grid.GetLength(0); i++)
            {
                for (int j = 0; j < grid.GetLength(1); j++)
                {
                    if (grid[i, j] == Action.Dig)
                    {
                        ulRowIndex = (i < ulRowIndex) ? i : ulRowIndex;
                        ulColumnIndex = (j < ulColumnIndex) ? j : ulColumnIndex;

                        brRowIndex = (i > brRowIndex) ? i : brRowIndex;
                        brColumnIndex = (j > brColumnIndex) ? j : brColumnIndex;
                    }
                }
            }

            if (ulRowIndex == int.MaxValue && ulColumnIndex == int.MaxValue && brRowIndex == int.MinValue && brColumnIndex == int.MinValue)
            {
                throw new Exception("No tiles were selected for digging.");
            }
        }
        public void digTerrain(int startRowIndex, int startColumnIndex, Action[,] grid)
        {
            //check if df is active
            int hWnd = getWindowHandle();

            //check starting position
            if (startRowIndex == -1 && startColumnIndex == -1)
            {
                throw new Exception("No starting position specified.");
            }

            //find digging rectangle
            int ulRowIndex, ulColumnIndex;
            int brRowIndex, brColumnIndex;
            findRectangleDig(grid, out ulRowIndex, out ulColumnIndex, out brRowIndex, out brColumnIndex);

            //set cursor at upper left corner of digging rectangle
            moveCursor(hWnd, startRowIndex, startColumnIndex, ulRowIndex, ulColumnIndex);
            int currentRowIndex = ulRowIndex;
            int currentColumnIndex = ulColumnIndex;

            //press d
            Keyboard.Instance.keyTap(hWnd, KeyboardKey.d);

            //select area to dig
            bool digging = false;
            for (int i = ulRowIndex; i <= brRowIndex; i++)
            {
                for (int j = ulColumnIndex; j <= brColumnIndex; j++)
                {
                    //move cursor
                    moveCursor(hWnd, currentRowIndex, currentColumnIndex, i, j);
                    currentRowIndex = i;
                    currentColumnIndex = j;

                    //start digging selection
                    if (!digging && grid[i, j] == Action.Dig)
                    {
                        Keyboard.Instance.keyTap(hWnd, KeyboardKey.enter);
                        digging = true;
                    }

                    //stop digging selection
                    int nextJ = (j < brColumnIndex) ? (j + 1) : j;
                    if (digging && grid[i, nextJ] != Action.Dig)
                    {
                        Keyboard.Instance.keyTap(hWnd, KeyboardKey.enter);
                        digging = false;
                    }
                }

                //stop digging when switching rows
                if (digging)
                {
                    Keyboard.Instance.keyTap(hWnd, KeyboardKey.enter);
                    digging = false;
                }
            }
        }
    }
}
